﻿//-----------------------------------------------------------------------------
//<filedescription file="IntegrationKit.SccmGeneral.cs" company="Microsoft">
//  <copyright>
//     Copyright © Microsoft Corporation.  All rights reserved.
//     ***  DESIGNATED SAMPLE CODE (per the included software license terms) ***
//      THIS CODE SAMPLE IS MADE AVAILABLE TO YOU WITHOUT WARRANTY OF ANY KIND
//      AND CONFERS NO RIGHTS ON YOU WHATSOEVER EXCEPT THE RIGHT TO REVIEW IT
//      SOLELY AS A REFERENCE.  THE ENTIRE RISK OF USE OR RESULTS FROM USE OF
//      THIS CODE SAMPLE REMAINS WITH YOU.
//  </copyright>
//  <purpose>
//     Provides general utility methods for interfacing with Configuration Manager
//  </purpose>
//  <notes>
//  </notes>
//</filedescription>
//-----------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Xml;
using Microsoft.ConfigurationManagement.AdminConsole;
using Microsoft.ConfigurationManagement.ManagementProvider;
using Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine;
using Microsoft.Win32;
using System.Windows.Forms;


namespace Microsoft.ConfigurationManagement.IntegrationDevelopmentKit
{
    /// <summary>
    /// 
    /// </summary>
    public partial class IntegrationKitUtilities
    {

        #region Property Manager
        /// <summary>
        /// Reads the PropertyManager for the current custom action and returns the specified string value, if it exists.
        /// </summary>
        /// <param taskName="propertyManager">The current PropertyManager object passed to the custom action by SCCM.</param>
        /// <param taskName="propertyName">The name of the property you wish to retrieve the value for.</param>
        /// <returns>A string containing the value of the property. Returns a null if the property name is not found.</returns>
        public static string GetPropertyManagerStringProperty(IResultObject propertyManager, string propertyName)
        {
            // LogLine(LogFile, " :: GetPropertyManagerStringProperty: Trying to get the " + propertyName + " value from PropertyManager");

            try
            {
                if ((propertyName != null) && (propertyManager[propertyName].ObjectValue != null) && (propertyManager[propertyName].StringValue != null))
                {
                    // LogLine(LogFile, " :: ->GetPropertyManagerStringProperty:\t'" + propertyName + "' value is : '" + propertyManager[propertyName].StringValue + "'");
                    return propertyManager[propertyName].StringValue;
                }
                else
                {
                    // LogLine(LogFile, " :: ->GetPropertyManagerStringProperty:\t'" + propertyName + "' value was null.");
                    return null;
                }
            }
            catch (Exception e)
            {
                DialogHelper.ShowMessageBox(e.Message);
                // LogLine(LogFile, "->GetPropertyManagerStringProperty:\tError:\tException catch statement reached in GetPMProperty. Error message follows:");
                LogException(logFile, e, debugEnabled);
                return null;
            }
        }

        /// <summary>
        /// Reads the PropertyManager for the current custom action and returns the specified boolean value, if it exists.
        /// </summary>
        /// <param taskName="propertyManager">The current PropertyManager object passed to the custom action by SCCM.</param>
        /// <param taskName="propertyName">The name of the property you wish to retrieve the value for.</param>
        /// <returns>A boolean containing the value of the property. Returns 'false' if the property name is not found.</returns>
        public static bool GetPropertyManagerBooleanProperty(IResultObject propertyManager, string propertyName)
        {
            // LogLine(LogFile, " :: GetPropertyManagerBooleanProperty: Trying to get the '" + propertyName + "' value from PropertyManager");

            try
            {
                if ((propertyName != null) && (propertyManager[propertyName].ObjectValue != null))
                {
                    // LogLine(LogFile, " :: ->GetPropertyManagerBooleanProperty:\t'" + propertyName + "' value is : '" + propertyManager[propertyName].BooleanValue + "'");
                    return propertyManager[propertyName].BooleanValue;
                }
                else
                {
                    // LogLine(LogFile, " :: ->GetPropertyManagerBooleanProperty:\t'" + propertyName + "' value was null. Returning 'false'");
                    return false;
                }
            }
            catch (Exception e)
            {
                DialogHelper.ShowMessageBox(e.Message);
                // LogLine(LogFile, "->GetPropertyManagerBooleanProperty:\tError:\tException catch statement reached iGetPropertyManagerBooleanPropertyty. Error message follows:");
                LogException(logFile, e, debugEnabled);
                return false;
            }
        }

        /// <summary>
        /// Reads the PropertyManager for the current custom action and returns the specified integer value, if it exists.
        /// </summary>
        /// <param taskName="propertyManager">The current PropertyManager object passed to the custom action by SCCM.</param>
        /// <param taskName="propertyName">The name of the property you wish to retrieve the value for.</param>
        /// <returns>An integer containing the value of the property. Returns null if the property name is not found.</returns>
        public static Nullable<int> GetPropertyManagerIntegerProperty(IResultObject propertyManager, string propertyName)
        {
            // LogLine(LogFile, " :: GetPropertyManagerIntegerProperty: Trying to get the '" + propertyName + "' value from PropertyManager");

            try
            {
                if ((propertyName != null) && (propertyManager[propertyName].ObjectValue != null))
                {
                    // LogLine(LogFile, " :: ->GetPropertyManagerIntegerProperty:\t'" + propertyName + "' value is : '" + propertyManager[propertyName].IntegerValue + "'");
                    return propertyManager[propertyName].IntegerValue;
                }
                else
                {
                    // LogLine(LogFile, " :: ->GetPropertyManagerIntegerProperty:\t'" + propertyName + "' value was null. Returning null.");
                    return null;
                }
            }
            catch (Exception e)
            {
                // LogLine(LogFile, "->GetPropertyManagerIntegerProperty:\tError:\tException catch statement reached iGetPropertyManagerIntegerPropertyty. Error message follows:");
                LogException(logFile, e, debugEnabled);
                return null;
            }
        }

        /// <summary>
        /// Stores the string value of an XML document in a specified property name in the PropertyManager for the current custom action.
        /// </summary>
        /// <param taskName="propertyManager">The current PropertyManager object passed to the custom action by SCCM.</param>
        /// <param taskName="propertyName">The name of the property you wish to store the XML document in.</param>
        /// <param taskName="doc">The XML document object read the string from.</param>
        /// <returns>A string containing the value of the property. Returns a null if the property name is not found.</returns>
        public static bool SaveXmlToPropertyManager(IResultObject propertyManager, string propertyName, XmlDocument doc)
        {
            try
            {
                if (propertyManager != null)
                {
                    if (!string.IsNullOrEmpty(propertyName))
                    {
                        if (doc != null)
                        {
                            propertyManager[propertyName].StringValue = doc.OuterXml;
                            // LogLine(LogFile, "SaveXmlToPropertyManager: Saved property XML to PropertyManager. Value from Property Manager: \n\n" + propertyManager[propertyName].StringValue + "\n\n");
                            return true;
                        }
                        else
                        {
                            // LogLine(LogFile, "SaveXmlToPropertyManager: Xml document passed in was null!");
                            return false;
                        }
                    }
                    else
                    {
                        // LogLine(LogFile, "SaveXmlToPropertyManager: Property taskName passed in was null!");
                        return false;
                    }
                }
                else
                {
                    // LogLine(LogFile, "SaveXmlToPropertyManager: PropertyManager object passed in was null!");
                    return false;
                }
            }
            catch (Exception e)
            {
                LogException(logFile, e, debugEnabled);
                return false;
            }
        }

        /// <summary>
        /// Reads the PropertyManager for the current custom action and returns the specified XML document object from a property, if it exists.
        /// </summary>
        /// <param taskName="propertyManager">The current PropertyManager object passed to the custom action by SCCM.</param>
        /// <param taskName="propertyName">The name of the property you wish to retrieve the XML object for.</param>
        /// <returns>An XmlDocument object containing the value of the property. Returns a null if the property name is not found.</returns>
        public static XmlDocument GetXmlFromPropertyManager(IResultObject propertyManager, string propertyName)
        {
            // LogLine(LogFile, "GetXmlFromPropertyManager: starting...");
            try
            {
                XmlDocument values = new XmlDocument();
                string content = GetPropertyManagerStringProperty(propertyManager, propertyName);
                if (content != null)
                {
                    //// LogLine(LogFile, "GetXmlFromPropertyManager: Found xml content in property manager: \n" + content);
                    values.LoadXml(content);
                    //// LogLine(LogFile, "Loaded XML content:\n" + values.OuterXml);
                    return values;
                }
                else
                {
                    // LogLine(LogFile, "GetXmlFromPropertyManager: Value in property manager was null for: " + propertyName);
                    return null;
                }
            }
            catch (Exception e)
            {
                LogException(logFile, e, debugEnabled);
                return null;
            }
        }


        #endregion

        #region IResultObjects

        /// <summary>
        ///     Gets the number of child IResultObjects in a parent IResultObject. Allows you to avoid the exception
        ///     that occurs when you use the Count property on an IResultObject and the object is singular or invalid.
        /// </summary>
        /// <param name="parent" type="Microsoft.ConfigurationManagement.ManagementProvider.IResultObject">
        ///     <para>
        ///         The object for which children (if any) are counted
        ///     </para>
        /// </param>
        /// <returns>
        ///     A int value...
        /// </returns>
        public static int GetNumberOfChildObjects(IResultObject parent)
        {
            if (parent == null)
            {
                throw new ArgumentNullException("parent");
            }
            try
            {
                //modified 12/10/09 by rhearn
                // Fix for codeplex issue 6416. Created a new IResultObject 'parentCopy' and copied the 'parent' object passed in 
                //  and enumerated the contents of 'parentCopy', so that the original object's enumerator is not modifiued

                IResultObject parentCopy = parent;

                int num = 0;
                if (parentCopy != null)
                {
                    foreach (IResultObject child in parentCopy)
                    {
                        num++;
                    }
                    return num;
                }
                else
                {
                    return 0;
                }
            }
            catch (Exception e)
            {
                LogException(LogFile, e);
                return 0;
            }
        }


        private void PrintAllObjectProperties(IResultObject itemObject)
        {
            try
            {
                if (itemObject == null)
                {
                    throw new System.ArgumentException("itemObject", Properties.Resources.Error_InvalidParameter);
                }

                try
                {
                    //this will refresh the object and get lazy properties.
                    itemObject.Get();
                }
                catch (NotImplementedException)
                {
                    //do nothing here if a not implemented exception occurs - just skip it
                }


                //Console.WriteLine("Object Type: " + itemObject.GetType().Name.ToString() + "\n");

                //Console.WriteLine("  Properties:");
                //Console.WriteLine("  ---------------");

                foreach (string propertyName in itemObject.PropertyNames)
                {
                    //Console.WriteLine("\n  Property name: " + propertyName);

                    if ((itemObject.Properties[propertyName].IsArray) ||
                        (string.Compare(itemObject.Properties[propertyName].GetType().ToString(), "IResultObject", StringComparison.OrdinalIgnoreCase) == 0))
                    {
                        List<IResultObject> newItemObject = itemObject.GetArrayItems(propertyName);

                        //Console.WriteLine("  Property '" + propertyName + " ' has :  " + newItemObject.Count + " sub-objects");

                        //List<IResultObject>.Enumerator newItemEnumerator = newItemObject.GetEnumerator();
                        //for (int i = 0; i < newItemObject.Count; i++)
                        //{
                        //    PrintAllObjectProperties(newItemEnumerator.Current);
                        //    newItemEnumerator.MoveNext();
                        //}
                    }

                    AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData dataType = itemObject.Properties[propertyName].DataType;
                    string strType = Enum.GetName(typeof(AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData), dataType);
                    //Console.WriteLine("           type: " + strType);
                    string value = string.Empty;
                    try
                    {
                        switch (dataType)
                        {
                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.String:
                                value = itemObject.Properties[propertyName].StringValue;
                                break;

                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.Long:
                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.InvariantLong:
                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.Integer:
                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.InvariantInteger:
                                value = itemObject.Properties[propertyName].IntegerValue.ToString();
                                break;

                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.Boolean:
                                value = itemObject.Properties[propertyName].BooleanValue.ToString();
                                break;

                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.DateTime:
                                value = itemObject.Properties[propertyName].DateTimeValue.ToString();
                                break;

                            default:
                                break;
                        }
                    }
                    catch (Exception)
                    {
                        //ignore
                    }
                    //Console.WriteLine("          value: " + value);
                    //Console.WriteLine("---------------------------");


                }
                return;

            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex);
                
            }
        }


        /// <summary>
        /// Reads an IResultObject and returns the value (string) in the specified property name, if it exists.
        /// </summary>
        /// <param taskName="objectName">An IResultObject that is to be searched.</param>
        /// <param taskName="propertyName">The name of the property you wish to retrieve the value for.</param>
        /// <returns>A string containing the value of the property. Returns a null if the property name is not found.</returns>
        public static string GetROStringProperty(IResultObject objectName, string propertyName)
        {
            if (objectName == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "objectName");
            }
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "propertyName");
            }

            
            try
            {
                ////Console.WriteLine("In GetROStringProperty(). \n");
                ////Console.WriteLine("Object type passed in : " + objectName.GetType().Name + " \n");
                ////Console.WriteLine("Property passed in    : '" + propertyName + "' \n");

                try
                {
                    //this will refresh the object and get lazy properties.
                    objectName.Get();
                }
                catch (NotImplementedException)
                {
                    //do nothing here if a not implemented exception occurs - just skip it
                }

                if (objectName.PropertyList.ContainsKey(propertyName))
                {
                    ////Console.WriteLine("Property '" + propertyName + "'exists. \n");
                    ////Console.WriteLine("Property type is " + objectName.Properties[propertyName].DataType.ToString() +"\n");
                    if (string.Compare(objectName.Properties[propertyName].DataType.ToString(), "String", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        ////Console.WriteLine("String value for '" + propertyName + "' property is '" + objectName.Properties[propertyName].StringValue + "' \n");
                        return objectName.Properties[propertyName].StringValue;
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }
            catch (SmsQueryException qex)
            {
                ////Console.WriteLine("Exception occurred in GetROStringProperty() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace);
                IntegrationKitUtilities.LogException(LogFile, qex);
                return null;
            }
            catch (Exception ex)
            {
                //DialogHelper.ShowMessageBox(exceptionInfo.Message);
                // LogLine(LogFile, "->GetROStringProperty:\tERROR:\tException catch statement reached in GetROStringProperty. Error message follows:");
                ////Console.WriteLine("Exception occurred in GetROStringProperty() : " + e.Message); 
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// Reads an IResultObject and returns the value (DateTime)in the specified property name, if it exists.
        /// </summary>
        /// <param taskName="objectName">An IResultObject that is to be searched.</param>
        /// <param taskName="propertyName">The name of the property you wish to retrieve the value for.</param>
        /// <returns>A DateTime object containing the value of the property. Returns DateTime.MinValue if the property name is not found.</returns>
        public static DateTime GetRODateTimeProperty(IResultObject objectName, string propertyName)
        {
            if (objectName == null)
            {
                throw new System.ArgumentException("objectName", Properties.Resources.Error_InvalidParameter);
            }
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new System.ArgumentException("propertyName", Properties.Resources.Error_InvalidParameter);
            }
            try
            {

                try
                {
                    //this will refresh the object and get lazy properties.
                    objectName.Get();
                }
                catch (NotImplementedException)
                {
                    //do nothing here if a not implemented exception occurs - just skip it
                }

                if (objectName.PropertyList.ContainsKey(propertyName))
                {
                    if (string.Compare(objectName.Properties[propertyName].DataType.ToString(), "DateTime", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return objectName.Properties[propertyName].DateTimeValue;
                    }
                    else
                    {
                        return DateTime.MinValue;
                    }
                }
                else
                {
                    return DateTime.MinValue;
                }

            }
            catch (Exception ex)
            {
                IntegrationKitUtilities.LogException(LogFile, ex);
                return DateTime.MinValue;
            }
        }

        /// <summary>
        /// Reads an IResultObject and returns the value (integer) in the specified property name, if it exists.
        /// </summary>
        /// <param taskName="objectName">An IResultObject that is to be searched.</param>
        /// <param taskName="propertyName">The name of the property you wish to retrieve the value for.</param>
        /// <returns>An integer containing the value of the property. Returns null if the property name is not found.</returns>
        public static Nullable<int> GetROIntegerProperty(IResultObject objectName, string propertyName)
        {
            ////Console.WriteLine("In GetROIntegerProperty(). \n");
            ////Console.WriteLine("Object type passed in : " + objectName.GetType().Name + " \n");
            ////Console.WriteLine("Property passed in    : '" + propertyName + "' \n");
            if (objectName == null)
            {
                throw new System.ArgumentException("objectName", Properties.Resources.Error_InvalidParameter);
            }
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new System.ArgumentException("propertyName", Properties.Resources.Error_InvalidParameter);
            }
            try
            {

                try
                {
                    //this will refresh the object and get lazy properties.
                    objectName.Get();
                }
                catch (NotImplementedException)
                {
                    //do nothing here if a not implemented exception occurs - just skip it
                }

                if (objectName.PropertyList.ContainsKey(propertyName))
                {
                    ////Console.WriteLine("Property '" + propertyName + "'exists. \n");
                    ////Console.WriteLine("Property type is " + objectName.Properties[propertyName].DataType.ToString() + "\n");
                    if ((string.Compare(objectName.Properties[propertyName].DataType.ToString(), "Integer", StringComparison.OrdinalIgnoreCase) == 0) ||
                        (string.Compare(objectName.Properties[propertyName].DataType.ToString(), "InvariantInteger", StringComparison.OrdinalIgnoreCase) == 0) ||
                        (string.Compare(objectName.Properties[propertyName].DataType.ToString(), "Long", StringComparison.OrdinalIgnoreCase) == 0) ||
                        (string.Compare(objectName.Properties[propertyName].DataType.ToString(), "InvariantLong", StringComparison.OrdinalIgnoreCase) == 0))
                    {
                        ////Console.WriteLine("Integer value for '" + propertyName + "' property is '" + objectName.Properties[propertyName].IntegerValue + "' \n");
                        return objectName.Properties[propertyName].IntegerValue;
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }
            catch (Exception ex)
            {
                //Console.WriteLine("Exception occurred in GetROIntegerProperty() : " + e.Message);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
        }

        /// <summary>
        /// Reads an IResultObject and returns the value (boolean) in the specified property name, if it exists.
        /// </summary>
        /// <param taskName="objectName">An IResultObject that is to be searched.</param>
        /// <param taskName="propertyName">The name of the property you wish to retrieve the value for.</param>
        /// <returns>A boolean containing the value of the property. Returns false if the property name is not found.</returns>
        public static bool GetROBooleanProperty(IResultObject objectName, string propertyName)
        {
            if (objectName == null)
            {
                throw new System.ArgumentException("objectName", Properties.Resources.Error_InvalidParameter);
            }
            if (string.IsNullOrEmpty(propertyName))
            {
                throw new System.ArgumentException("propertyName", Properties.Resources.Error_InvalidParameter);
            }
            try
            {

                try
                {
                    //this will refresh the object and get lazy properties.
                    objectName.Get();
                }
                catch (NotImplementedException)
                {
                    //do nothing here if a not implemented exception occurs - just skip it
                }

                if (objectName.PropertyList.ContainsKey(propertyName))
                {
                    if (string.Compare(objectName.Properties[propertyName].DataType.ToString(), "Boolean", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        return objectName.Properties[propertyName].BooleanValue;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
            catch (Exception ex)
            {
                ////Console.WriteLine("Exception occurred in GetROBooleanProperty() : " + e.Message);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return false;
            }
        }

        /// <summary>
        /// Finds the appropriate string representing the unique instance ID of the object depending on object type.
        /// </summary>
        /// <param name="itemObject"></param>
        /// <param name="objectType"></param>
        /// <returns>A string with the instance ID, or null if not found or an error occurs.</returns>
        public static string GetObjectInstanceID(IResultObject itemObject, ContainerItemType objectType)
        {
            if (itemObject == null)
            {
                throw new System.ArgumentException("itemObject", Properties.Resources.Error_InvalidParameter);
            }
            if (objectType < 0)
            {
                throw new System.ArgumentException("objectType", Properties.Resources.Error_InvalidParameter);
            }
            try
            {

                try
                {
                    //this will refresh the object and get lazy properties.
                    itemObject.Get();
                }
                catch (NotImplementedException)
                {
                    //do nothing here if a not implemented exception occurs - just skip it
                }

                string instanceID = string.Empty;

                switch (objectType)
                {
                    case ContainerItemType.Advertisement:
                        instanceID = GetROStringProperty(itemObject, "AdvertisementID");
                        break;

                    case ContainerItemType.Driver:
                    case ContainerItemType.SoftwareUpdate:
                    case ContainerItemType.ConfigurationBaseline:
                    case ContainerItemType.ConfigurationItem:
                        instanceID = GetROStringProperty(itemObject, "CI_UniqueID");
                        break;

                    case ContainerItemType.DeviceSettingPackage:
                    case ContainerItemType.ImagePackage:
                    case ContainerItemType.DriverPackage:
                    case ContainerItemType.BootImagePackage:
                    case ContainerItemType.Package:
                    case ContainerItemType.TaskSequencePackage:
                        instanceID = GetROStringProperty(itemObject, "PackageID");
                        break;

                    case ContainerItemType.Query:
                        instanceID = GetROStringProperty(itemObject, "QueryID");
                        break;

                    case ContainerItemType.Report:
                        instanceID = GetROStringProperty(itemObject, "ReportID");
                        break;

                    case ContainerItemType.MeteredProductRule:
                        instanceID = GetROStringProperty(itemObject, "RuleID");
                        break;

                    case ContainerItemType.StateMigration:
                        instanceID = GetROStringProperty(itemObject, "MigrationID");
                        break;

                    case ContainerItemType.None:
                        // not used
                        break;

                    default:
                        // not used
                        break;
                }
                return instanceID;

            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="itemName"></param>
        /// <param name="objectType"></param>
        /// <param name="version"></param>
        /// <returns></returns>
        public static IResultObject GetPackageByName(WqlConnectionManager connection, string itemName, PackageType objectType, string version)
        {
            if (connection == null)
            {
                throw new System.ArgumentNullException("connection", Properties.Resources.Error_InvalidParameter);
            }
            if (string.IsNullOrEmpty(itemName))
            {
                throw new System.ArgumentNullException("itemName", Properties.Resources.Error_InvalidParameter);
            }
            if (objectType < 0)
            {
                throw new System.ArgumentNullException("objectType", Properties.Resources.Error_InvalidParameter);
            }

            // version can be null

            try
            {
                
                string query = string.Empty;
                itemName = FixWmiQueryString(itemName);

                //MessageBox.Show("DEBUG:\n\nGetPackageByName(). Searching for : " + itemName + ", version " + version + ".");

                switch (objectType)
                {
                    case PackageType.BootImagePackage:
                        query = "Select * From SMS_BootImagePackage Where Name LIKE '" + itemName + "'";
                        break;

                    case PackageType.DeviceSettingPackage:
                        query = "Select * From SMS_DeviceSettingPackage  Where Name LIKE '" + itemName + "'";
                        break;

                    case PackageType.DriverPackage:
                        query = "Select * From SMS_DriverPackage Where Name LIKE '" + itemName + "'";
                        break;

                    case PackageType.OSImagePackage:
                        query = "Select * From SMS_ImagePackage Where Name LIKE '" + itemName + "'";
                        break;

                    case PackageType.OSInstallPackage:
                        query = "Select * From SMS_OperatingSystemInstallPackage Where Name LIKE '" + itemName + "'";
                        break;

                    case PackageType.SoftwareUpdatePackage:
                        query = "Select * From SMS_SoftwareUpdatesPackage Where Name LIKE '" + itemName + "'";
                        break;

                    case PackageType.SWDPackage:
                        query = "Select * From SMS_Package Where Name LIKE '" + itemName + "'";
                        break;

                    case PackageType.TaskSequencePackage:
                        query = "Select * From SMS_TaskSequencePackage Where Name LIKE '" + itemName + "'";
                        break;

                    default:
                        // not used
                        break;
                }

                if (string.IsNullOrEmpty(query))
                {
                    return null;
                }

                //MessageBox.Show("DEBUG:\n\nSearch string is '" + query + "'\n");

                IResultObject packages = ExecuteNullableQuery(connection, query);
                if (packages == null)
                {
                    return null;
                }
                if (string.IsNullOrEmpty(version))
                {
                    foreach (IResultObject package in packages)
                    {
                        if (package != null) 
                        {
                            string packageID = GetROStringProperty(package, "PackageID");
                            if (string.IsNullOrEmpty(packageID) == false)
                            {
                                //MessageBox.Show("DEBUG:\n\nfound package ID '" + packageID + "'\n");

                                return package;
                            }
                        }
                    }
                }
                else
                {
                    foreach (IResultObject package in packages)
                    {
                        string packageID = GetROStringProperty(package, "PackageID");
                        string pkgVersion = GetROStringProperty(package, "Version");
                        if (package != null)
                        {
                            //MessageBox.Show("DEBUG:\n\nfound package ID '" + packageID + "' with version '" + pkgVersion + "'");

                            if ((string.IsNullOrEmpty(packageID) == false) && 
                                (string.IsNullOrEmpty(pkgVersion) == false) &&
                                (string.Compare(pkgVersion, version, StringComparison.OrdinalIgnoreCase) == 0))
                            {
                                return package;
                            }
                        }
                    }
                }
                return null;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="itemId"></param>
        /// <param name="objectType"></param>
        /// <returns></returns>
        public static IResultObject GetPackageById(WqlConnectionManager connection, string itemId, PackageType objectType)
        {
            if (connection == null)
            {
                throw new System.ArgumentNullException("connection", Properties.Resources.Error_InvalidParameter);
            }
            if (string.IsNullOrEmpty(itemId))
            {
                throw new System.ArgumentNullException("itemId", Properties.Resources.Error_InvalidParameter);
            }
            if (objectType < 0)
            {
                throw new System.ArgumentNullException("objectType", Properties.Resources.Error_InvalidParameter);
            }

           
            try
            {
                string query = string.Empty;

                //Console.WriteLine("GetPackageById(). Searching for : " + itemId + ".\n");

                switch (objectType)
                {
                    case PackageType.BootImagePackage:
                        query = "Select * From SMS_BootImagePackage Where PackageID='" + itemId + "'";
                        break;

                    case PackageType.DeviceSettingPackage:
                        query = "Select * From SMS_DeviceSettingPackage  Where PackageID='" + itemId + "'";
                        break;

                    case PackageType.DriverPackage:
                        query = "Select * From SMS_DriverPackage Where PackageID='" + itemId + "'";
                        break;

                    case PackageType.OSImagePackage:
                        query = "Select * From SMS_ImagePackage Where PackageID='" + itemId + "'";
                        break;

                    case PackageType.OSInstallPackage:
                        query = "Select * From SMS_OperatingSystemInstallPackage  Where PackageID='" + itemId + "'";
                        break;

                    case PackageType.SoftwareUpdatePackage:
                        query = "Select * From SMS_SoftwareUpdatesPackage Where PackageID='" + itemId + "'";
                        break;

                    case PackageType.SWDPackage:
                        query = "Select * From SMS_Package Where PackageID='" + itemId + "'";
                        break;

                    case PackageType.TaskSequencePackage:
                        query = "Select * From SMS_TaskSequencePackage   Where PackageID='" + itemId + "'";
                        break;

                    default:
                        // not used
                        break;
                }

                if (string.IsNullOrEmpty(query))
                {
                    return null;
                }

                //Console.WriteLine("Search string is '" + query + "'\n");

                IResultObject packages = ExecuteNullableQuery(connection, query);
                if (packages == null)
                {
                    return null;
                }
                else
                {
                    foreach (IResultObject package in packages)
                    {
                        return package;
                    }
                }
                return null;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="itemName"></param>
        /// <param name="objectType"></param>
        /// <returns></returns>
        public static IResultObject GetContainerItemByName(WqlConnectionManager connection, string itemName, ContainerItemType objectType)
        {
            if (connection == null)
            {
                throw new System.ArgumentException("connection", Properties.Resources.Error_InvalidParameter);
            }
            if (string.IsNullOrEmpty(itemName))
            {
                throw new System.ArgumentException("itemName", Properties.Resources.Error_InvalidParameter);
            }
            if (objectType < 0)
            {
                throw new System.ArgumentException("objectType", Properties.Resources.Error_InvalidParameter);
            }
            try
            {
                string query = string.Empty;
                bool lazy = false;
                string lazyProperty = string.Empty;
                itemName = FixWmiQueryString(itemName);

                switch (objectType)
                {

                    case ContainerItemType.Advertisement:
                        query = "Select * From SMS_Advertisement  Where AdvertisementName='" + itemName + "'";
                        break;

                    case ContainerItemType.Driver:
                        //
                        //   Requires reading a lazy property of SMS_CI_LocalizedProperties Array / LocalizedDisplayName 
                        //
                        query = "Select * From SMS_Driver";
                        lazy = true;
                        lazyProperty = "LocalizedDisplayName";

                        break;

                    case ContainerItemType.SoftwareUpdate:
                        //
                        //   Requires reading a lazy property of SMS_CI_LocalizedProperties Array / LocalizedDisplayName 
                        //
                        query = "Select * From SMS_SoftwareUpdate";
                        lazy = true;
                        lazyProperty = "LocalizedDisplayName";
                        break;


                    case ContainerItemType.ConfigurationBaseline:
                        //
                        //   Requires reading a lazy property of SMS_CI_LocalizedProperties Array / LocalizedDisplayName 
                        //
                        query = "Select * From SMS_ConfigurationBaseline";
                        lazy = true;
                        lazyProperty = "LocalizedDisplayName";
                        break;

                    case ContainerItemType.ConfigurationItem:
                        //
                        //   Requires reading a lazy property of SMS_CI_LocalizedProperties Array / LocalizedDisplayName 
                        //
                        query = "Select * From SMS_ConfigurationItem";
                        lazy = true;
                        lazyProperty = "LocalizedDisplayName";
                        break;

                    case ContainerItemType.DeviceSettingPackage:
                        query = "Select * From SMS_DeviceSettingPackage Where Name='" + itemName + "'";
                        break;

                    case ContainerItemType.ImagePackage:
                        query = "Select * From SMS_ImagePackage Where Name='" + itemName + "'";
                        break;

                    case ContainerItemType.OperatingSystemInstallPackage:
                        query = "Select * From SMS_OperatingSystemInstallPackage Where Name='" + itemName + "'";
                        break;

                    case ContainerItemType.DriverPackage:
                        query = "Select * From SMS_DriverPackage Where Name='" + itemName + "'";
                        break;

                    case ContainerItemType.BootImagePackage:
                        query = "Select * From SMS_BootImagePackage Where Name='" + itemName + "'";
                        break;

                    case ContainerItemType.Package:
                        query = "Select * From SMS_Package Where Name='" + itemName + "'";
                        break;

                    case ContainerItemType.TaskSequencePackage:
                        query = "Select * From SMS_TaskSequencePackage   Where Name='" + itemName + "'";
                        break;

                    case ContainerItemType.Query:
                        query = "Select * From SMS_Query Where Name='" + itemName + "'";
                        break;

                    case ContainerItemType.Report:
                        query = "Select * From SMS_Report Where Name='" + itemName + "'";
                        break;

                    case ContainerItemType.MeteredProductRule:
                        query = "Select * From SMS_MeteredProductRule  Where ProductName='" + itemName + "'";
                        break;

                    case ContainerItemType.StateMigration:
                        query = "Select * From SMS_StateMigration Where SourceName='" + itemName + "'";
                        break;

                    case ContainerItemType.None:
                        // not used
                        break;

                    default:
                        // not used
                        break;
                }
                if (string.IsNullOrEmpty(query))
                {
                    return null;
                }

                IResultObject packages = ExecuteNullableQuery(connection, query);
                if (packages == null)
                {
                    return null;
                }
                if (lazy == true)
                {
                    foreach (IResultObject package in packages)
                    {
                        try
                        {
                            //this will refresh the object and get lazy properties.
                            package.Get();
                        }
                        catch (NotImplementedException)
                        {
                            //do nothing here if a not implemented exception occurs - just skip it
                        }
                        string propertyValue = GetROStringProperty(package, lazyProperty);
                        if (string.Compare(propertyValue, itemName, StringComparison.CurrentCultureIgnoreCase) == 0)
                        {
                            return package;
                        }
                    }
                    return null;
                }
                return packages;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// Obtains a list of all ConfigMgr packages of a specified type. Returns null if none found.
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="objectType"></param>
        /// <returns></returns>
        public static List<IResultObject> GetAllPackagesByType(WqlConnectionManager connection, PackageType objectType)
        {
            if (connection == null)
            {
                throw new System.ArgumentNullException("connection", Properties.Resources.Error_InvalidParameter);
            }
            if (objectType < 0)
            {
                throw new System.ArgumentNullException("objectType", Properties.Resources.Error_InvalidParameter);
            }


            try
            {
                string query = string.Empty;

                //Console.WriteLine("GetPackageByName(). Searching for : " + itemId + ".\n");

                switch (objectType)
                {
                    case PackageType.BootImagePackage:
                        query = "Select * From SMS_BootImagePackage";
                        break;

                    case PackageType.DeviceSettingPackage:
                        query = "Select * From SMS_DeviceSettingPackage";
                        break;

                    case PackageType.DriverPackage:
                        query = "Select * From SMS_DriverPackage";
                        break;

                    case PackageType.OSImagePackage:
                        query = "Select * From SMS_ImagePackage";
                        break;

                    case PackageType.OSInstallPackage:
                        query = "Select * From SMS_OperatingSystemInstallPackage";
                        break;

                    case PackageType.SoftwareUpdatePackage:
                        query = "Select * From SMS_SoftwareUpdatesPackage";
                        break;

                    case PackageType.SWDPackage:
                        query = "Select * From SMS_Package";
                        break;

                    case PackageType.TaskSequencePackage:
                        query = "Select * From SMS_TaskSequencePackage";
                        break;

                    default:
                        // not used
                        break;
                }

                if (string.IsNullOrEmpty(query))
                {
                    return null;
                }

                //Console.WriteLine("Search string is '" + query + "'\n");

                IResultObject packages = ExecuteNullableQuery(connection, query);
                if (packages != null)
                {
                    List<IResultObject> packageList = new List<IResultObject>();
                    foreach (IResultObject package in packages)
                    {
                        packageList.Add(package);
                    }
                    return packageList;
                }
                return null;
            }
            catch
            {
                return null;
            }
        }

        #endregion

        #region ConnectionManager

        /// <summary>
        /// Creates a WqlConnectionManager object which is a connection to the named site server.
        /// </summary>
        /// <param name="serverName"></param>
        /// <param name="userName"></param>
        /// <param name="userPassword"></param>
        /// <returns></returns>
        public static WqlConnectionManager Connect(string serverName, string userName, string userPassword)
        {
            try
            {
                SmsNamedValuesDictionary namedValues = new SmsNamedValuesDictionary();
                WqlConnectionManager connection = new WqlConnectionManager(namedValues);

                if (string.IsNullOrEmpty(serverName))
                {
                    connection.Connect(System.Net.Dns.GetHostName());
                }
                else if (System.Net.Dns.GetHostName().ToUpper() == serverName.ToUpper())
                {
                    // Connect to local computer.
                    connection.Connect(serverName);
                }
                else if ((string.IsNullOrEmpty(userName) == false) &&
                    (string.IsNullOrEmpty(userPassword) == false))
                {
                    // Connect to remote computer.
                    connection.Connect(serverName, userName, userPassword);
                }

                return connection;
            }
            catch (SmsException ex)
            {
                //Console.WriteLine("Failed to Connect. Error: " + e.Message);
                IntegrationKitUtilities.LogException(LogFile, ex);
                return null;
            }
            catch (UnauthorizedAccessException uex)
            {
                //Console.WriteLine("Failed to authenticate. Error:" + e.Message);
                IntegrationKitUtilities.LogException(LogFile, uex);
                return null;
            }
        }


        #endregion

        #region WMI

        /// <summary>
        /// 
        /// </summary>
        /// <param name="connection"></param>
        /// <param name="wqlQuery"></param>
        /// <returns></returns>
        public static IResultObject ExecuteNullableQuery(WqlConnectionManager connection, string wqlQuery)
        {
            if (connection == null)
            {
                throw new System.ArgumentNullException("connection");
            }
            if (string.IsNullOrEmpty(wqlQuery))
            {
                throw new System.ArgumentNullException("wqlQuery");
            }
            
            IResultObject results = null;

            try
            {
                int count = 0;
                results = connection.QueryProcessor.ExecuteQuery(wqlQuery);
                if (results != null)
                {
                    //LogLine(LogFile, "Query returned an object of type: " + obj.GetType().FullName, DebugEnabled);
                    foreach (IResultObject var in results)
                    {
                        count++;
                    }
                    if (count > 0)
                    {
                        return results;
                    }
                    else
                    {
                        return null;
                    }
                }

                return null;
            }
            catch (SmsQueryException ex)
            {
                LogException(LogFile, ex);
                return null;
            }
            catch (NotImplementedException ex2)
            {
                LogLine(LogFile, "Exception occurred when accessing properties of the query results. This means there were no results. Returning null.", DebugEnabled);
                LogException(LogFile, ex2);
                return null;
            }
            catch (NotSupportedException ex3)
            {
                LogLine(LogFile, "Exception occurred when accessing properties of the query results. This means there were no results. Returning null.", DebugEnabled);
                LogException(LogFile, ex3);
                return null;
            }

            finally
            {
                if (results != null)
                {
                    results.Dispose();
                }
            }
                
        }
       
        /// <summary>
        /// 
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        public static string FixWmiQueryString(string query)
        {
            if (string.IsNullOrEmpty(query) == false)
            {
                query = query.Replace("_", "[_]");
                query = query.Replace("'", "''");
                
            }
            return query;
        }


        #endregion


        /// <summary>
        ///     
        /// </summary>
        /// <param name="subKey" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <param name="valueName" type="string">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A string value...
        /// </returns>
        public static string GetConfigMgrRegistryStringValue(string subKey, string valueName)
        {
            string smsIdentificationRegKey = @"SOFTWARE\Microsoft\SMS";
            if (string.IsNullOrEmpty(subKey) == false)
            {
                smsIdentificationRegKey += "\\" + subKey;
            }
            string valueString = GetSafeRegistryStringValue("HKEY_LOCAL_MACHINE", smsIdentificationRegKey, valueName);

            return valueString;
        }


       


    }
}